﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Estimate
{
    enum ReportBudgetType { Budget, Act }

    public class Budget
    {
        ReportBudgetType budgetType;
        Object currentObject;
        EstimateDataContext context;
        DateTime dateTimeFrom;
        DateTime dateTimeTo;
        Db db;
        private string month;

        public Budget(EstimateDataContext context, Object currentObject, int year, int monthIndex,string month)
        {
            this.month = month;
            db = new Db(context);
            if (year == 0) budgetType = ReportBudgetType.Budget;
            else
            {
                budgetType = ReportBudgetType.Act;
                monthIndex ++;
                this.dateTimeFrom = new DateTime(year, monthIndex, 1);
                if (monthIndex == 12)
                {
                    monthIndex = 0;
                    year++;
                }
                this.dateTimeTo = new DateTime(year, monthIndex+1, 1);
            }
            


            this.context = context;
            this.currentObject = currentObject;
            budgetMain = new BudgetMain();
            FillBudgetMain();
        }

      

        public Budget(EstimateDataContext context, Object currentObject)
            : this(context, currentObject, 0,0,"")
        {}
    
        private BudgetMain budgetMain;
        private int number = 1;
        int chapterNumber = 0;

        private void FillBudgetMain()
        {
            //head
            budgetMain.Firm1 = currentObject.Firm.FirmName;
            budgetMain.Firm2 = db.GetFirmOwn().FirmName;
            budgetMain.ObjectAddress = currentObject.ObjectAddress;
            budgetMain.ObjectContract = string.Format("№ {0} від {1}", currentObject.ContractNumber,
                                                      currentObject.ContractDate);
            budgetMain.ObjectName = currentObject.ObjectName;
            if (budgetType == ReportBudgetType.Budget)
                budgetMain.ReportTitle = "Кошторисний Розрахунок";
            else
                budgetMain.ReportTitle =
                    string.Format("Акт №{0}-{1}/{2} приймання виконаних підрядних робіт за {3} {2} року",
                                  currentObject.ObjectID, dateTimeFrom.Month, dateTimeFrom.Year, month);
        
            //

            if (budgetType == ReportBudgetType.Budget)
            {
                foreach (ObjectWorkCategory objectWorkCategory in currentObject.ObjectWorkCategories)
                {
                    chapterNumber++;
                    BudgetDetail budgetDetail = new BudgetDetail();
                    budgetDetail.Title = string.Format("Розділ {0}: {1}", chapterNumber,
                                                       objectWorkCategory.ObjectWorkCategoryName);
                    List<ProductInInvoice> productInInvoice =
                        (from x in objectWorkCategory.BudgetWorks
                         select new ProductInInvoice()
                                    {
                                        Count = x.cnt,
                                        Price = x.Work.Price,
                                        PriceTotal = x.cnt*x.Work.Price,
                                        ProductName = x.Work.WorkName,
                                        UnitName = x.Work.Unit.UnitName
                                    }).ToList();
                    InsertDetailWork(budgetDetail, productInInvoice);
                    budgetMain.BudgetDetails.Add(budgetDetail);
                }


                chapterNumber++;
                BudgetDetail budgetDetailProduct = new BudgetDetail();
                budgetDetailProduct.Title = string.Format("Розділ {0}: Матеріали", chapterNumber);
                List<ProductInInvoice> productInInvoice2 =
                    (from x in currentObject.BudgetProducts
                     select new ProductInInvoice()
                                {
                                    //InvoiceToHistoryID = x.Product.ProductID,
                                    Price = getPrice(x.Product ),
                                        
                                    Count = x.cnt,
                                    ProductName = x.Product.ProductName,
                                    UnitName = x.Product.Unit.UnitName
                                }).ToList();
                InsertDetailProduct(budgetDetailProduct, productInInvoice2);
                budgetMain.BudgetDetails.Add(budgetDetailProduct);
            }
            else
            {
                foreach (ObjectWorkCategory objectWorkCategory in currentObject.ObjectWorkCategories)
                {
                    chapterNumber++;
                    BudgetDetail budgetDetail = new BudgetDetail();
                    budgetDetail.Title = string.Format("Розділ {0}: {1}", chapterNumber,
                                                       objectWorkCategory.ObjectWorkCategoryName);
                    List<ProductInInvoice> productInInvoice =
                        (from x in objectWorkCategory.ObjectWorks
                         where x.IsAdd == false && x.dateset >= dateTimeFrom && x.dateset <= dateTimeTo
                         select new ProductInInvoice()
                         {
                             Count = x.cnt,
                             Price = x.Work.Price,
                             PriceTotal = x.cnt * x.Work.Price,
                             ProductName = x.Work.WorkName,
                             UnitName = x.Work.Unit.UnitName
                         }).ToList();
                    InsertDetailWork(budgetDetail, productInInvoice);
                    budgetMain.BudgetDetails.Add(budgetDetail);
                }
                foreach (ObjectWorkCategory objectWorkCategory in currentObject.ObjectWorkCategories)
                {
                    chapterNumber++;
                    BudgetDetail budgetDetail = new BudgetDetail();
                    budgetDetail.Title = string.Format("Розділ {0}: {1} (додаткові роботи)", chapterNumber,
                                                       objectWorkCategory.ObjectWorkCategoryName);
                    List<ProductInInvoice> productInInvoice =
                        (from x in objectWorkCategory.ObjectWorks
                         where x.IsAdd == true && x.dateset >= dateTimeFrom && x.dateset <= dateTimeTo
                         select new ProductInInvoice()
                         {
                             Count = x.cnt,
                             Price = x.Work.Price,
                             PriceTotal = x.cnt * x.Work.Price,
                             ProductName = x.Work.WorkName,
                             UnitName = x.Work.Unit.UnitName
                         }).ToList();
                    InsertDetailWork(budgetDetail, productInInvoice);
                    budgetMain.BudgetDetails.Add(budgetDetail);
                }
            }

            //FoOTER
            decimal taxAdmin = reportTotal / 100 * (decimal)currentObject.TaxAdmin;
            decimal taxProfit = reportTotal / 100 * (decimal)currentObject.TaxProfit ;
            decimal taxSingle = reportTotal*context.Rates.Where(x => x.RateID == 13).First().RateValue;

            InsertFooter("Всього по всіх розділах кошторису", "грн.", 0,
                         decimal.Round(reportTotal, 3));
            InsertFooter("Адміністративні витрати", "грн.", (decimal)currentObject.TaxAdmin ,
                         decimal.Round(taxAdmin , 3));
            InsertFooter("Кошторисний прибуток", "грн.", (decimal)currentObject.TaxProfit,
                         decimal.Round(taxProfit, 3));

            if(currentObject.IsTaxSingle == true )
            {
                InsertFooter("Єдиний податок", "грн.", 6,
                         decimal.Round(taxSingle, 3));
                reportTotal += taxSingle;
            }
            reportTotal = reportTotal + taxAdmin + taxProfit;
            InsertFooter("Разом по Кошторису", "грн.", 0,
                     decimal.Round(reportTotal , 3));
            decimal VAT = reportTotal / 100 * (decimal)currentObject.TaxVat;
            InsertFooter("ПДВ", "грн.", (decimal)currentObject.TaxVat,
                     decimal.Round(VAT , 3));
            reportTotal += VAT;
            InsertFooter("Всього по Кошторису з ПДВ", "грн.", 0,
                     decimal.Round(reportTotal, 3));
        }

        private void InsertFooter(string name, string unit, decimal count, decimal pricetotal)
        {
            ProductInInvoice productInInvoice = new ProductInInvoice();
            productInInvoice.Count = count;
            productInInvoice.PriceTotal = pricetotal;
            productInInvoice.ProductName = name;
            productInInvoice.UnitName = unit;
            budgetMain.Footer.Add(productInInvoice);
        }

        private decimal getPrice(Product product)
        {
            decimal price;
            try
            {
                price = decimal.Round(product.ProductHistories.Where(y => y.StatusID == 10).OrderByDescending(
                                          y => y.ProductHistoryID).First().InvoiceIncomeToHistories.First().Price*
                                      (100 + currentObject.Rate.RateValue)/100*db.Dollar, 3);
                return price;
            }
            catch
            {
                return 0;
            }
        }

        private void InsertDetailProduct(BudgetDetail budgetDetail, List<ProductInInvoice> productInInvoice)
        {
            decimal total = 0;
            foreach (ProductInInvoice product in productInInvoice)
            {
                product.InvoiceToHistoryID = number;
                product.PriceTotal = decimal.Round(product.Price*product.Count, 3);
                budgetDetail.Products.Add(product);
                number++;
                total += product.PriceTotal;
            }
            InsertFooter(budgetDetail, "Всього", "грн.", 0, decimal.Round(total));

            decimal taxTransport = total / 100 * (decimal)currentObject.TaxTransport;
            decimal taxStoreHouse = total / 100 * (decimal)currentObject.TaxStorehouse;
            
            InsertFooter(budgetDetail, "Транспортні Витрати", "грн.", (decimal)currentObject.TaxTransport,
                         decimal.Round(taxTransport, 3));
            total += taxTransport;
            
            InsertFooter(budgetDetail, "Заготівельно-складські Витрати", "грн.", (decimal)currentObject.TaxStorehouse,
                         decimal.Round(taxStoreHouse, 3));
            total += taxTransport;
            InsertFooter(budgetDetail, "Всього по Розділу " + chapterNumber, "грн.", 0, decimal.Round(total));
            reportTotal += total;
        }

        private decimal reportTotal;

        private void InsertDetailWork(BudgetDetail budgetDetail, List<ProductInInvoice> productInInvoice)
        {
            decimal total = 0;
            foreach (ProductInInvoice product in productInInvoice)
            {
                product.InvoiceToHistoryID = number;
                product.PriceTotal = decimal.Round(product.PriceTotal, 3);
                budgetDetail.Products.Add(product);
                number++;
                total += product.PriceTotal;
            }
            InsertFooter(budgetDetail, "Всього", "грн.", 0, decimal.Round(total));
            decimal taxCurrent = total/100*(decimal) currentObject.TaxCurrent;
            InsertFooter(budgetDetail, "Накладні Витрати", "грн.", (decimal) currentObject.TaxCurrent,
                         decimal.Round(taxCurrent, 3));
            total += taxCurrent;
            InsertFooter(budgetDetail, "Всього по Розділу " + chapterNumber, "грн.", 0, decimal.Round(total));
            reportTotal += total;
        }

        private void InsertFooter(BudgetDetail budgetDetail, string name, string unit, decimal count, decimal pricetotal)
        {
            ProductInInvoice productInInvoice = new ProductInInvoice();
            productInInvoice.Count = count;
            productInInvoice.PriceTotal = pricetotal;
            productInInvoice.ProductName = name;
            productInInvoice.UnitName = unit;
            budgetDetail.Footer.Add(productInInvoice);
        }

    

        

        internal void ShowBudget()
        {
            ShowReport(ReportBudgetType.Budget);
        }

        internal void ShowAVR()
        {
            ShowReport(ReportBudgetType.Act );
            
        }

        private void ShowReport(ReportBudgetType reportBudgetType)
        {
            XtraReport1  reportBudget = new XtraReport1() ;

            


            reportBudget.bindingSource2.DataSource   = budgetMain;
            reportBudget.ShowPreview();
        }
    }
}
